package com.it.flowable.controller;

import com.it.flowable.dto.PageResult;
import com.it.flowable.dto.ProcessInstanceQueryDTO;
import com.it.flowable.dto.ProcessInstanceVO;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.flowable.engine.HistoryService;
import org.flowable.engine.RepositoryService;
import org.flowable.engine.RuntimeService;
import org.flowable.engine.TaskService;
import org.flowable.engine.history.HistoricProcessInstance;
import org.flowable.engine.repository.ProcessDefinition;
import org.flowable.engine.runtime.Execution;
import org.flowable.engine.runtime.ProcessInstance;
import org.flowable.engine.runtime.ProcessInstanceQuery;
import org.flowable.task.api.Task;
import org.flowable.variable.api.history.HistoricVariableInstance;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

@Service
@Slf4j
public class ProcessInstanceService {
    
    @Autowired
    private RuntimeService runtimeService;
    
    @Autowired
    private HistoryService historyService;
    
    @Autowired
    private RepositoryService repositoryService;
    
    @Autowired
    private TaskService taskService;

    public PageResult<ProcessInstanceVO> getSuspendedProcessInstances(ProcessInstanceQueryDTO queryDTO) {
        ProcessInstanceQuery runtimeQuery = runtimeService.createProcessInstanceQuery().suspended();
        
        if (StringUtils.isNotBlank(queryDTO.getProcessInstanceId())) {
            runtimeQuery.processInstanceId(queryDTO.getProcessInstanceId());
        }
        if (StringUtils.isNotBlank(queryDTO.getProcessDefinitionKey())) {
            runtimeQuery.processDefinitionKey(queryDTO.getProcessDefinitionKey());
        }
        
        long total = runtimeQuery.count();
        List<ProcessInstance> instances = runtimeQuery
                .orderByProcessInstanceId().desc()
                .listPage((queryDTO.getPage() - 1) * queryDTO.getSize(), queryDTO.getSize());
        
        List<ProcessInstanceVO> vos = instances.stream()
                .map(this::convertRuntimeToVO)
                .collect(Collectors.toList());
        
        return new PageResult<>(vos, total, queryDTO.getPage(), queryDTO.getSize());
    }
    
    public ProcessInstanceVO getProcessInstanceDetail(String processInstanceId) {
        // 先查询历史记录
        HistoricProcessInstance historicInstance = historyService.createHistoricProcessInstanceQuery()
                .processInstanceId(processInstanceId)
                .singleResult();
        
        if (historicInstance == null) {
            throw new RuntimeException("流程实例不存在: " + processInstanceId);
        }
        
        ProcessInstanceVO vo = convertToVO(historicInstance);
        
        // 获取流程变量
        Map<String, Object> variables = new HashMap<>();
        if (historicInstance.getEndTime() == null) {
            // 运行中的实例获取运行时变量
            variables = runtimeService.getVariables(processInstanceId);
        } else {
            // 已结束的实例获取历史变量
            List<HistoricVariableInstance> historicVariables = historyService.createHistoricVariableInstanceQuery()
                    .processInstanceId(processInstanceId)
                    .list();
            variables = historicVariables.stream()
                    .collect(Collectors.toMap(
                            HistoricVariableInstance::getVariableName,
                            HistoricVariableInstance::getValue
                    ));
        }
        vo.setVariables(variables);
        
        // 获取当前活动节点（仅运行中的实例）
        if (historicInstance.getEndTime() == null) {
            List<ProcessInstanceVO.ActivityInfo> currentActivities = getCurrentActivities(processInstanceId);
            vo.setCurrentActivities(currentActivities);
        }
        
        return vo;
    }
    
    public ProcessInstanceVO convertToVO(HistoricProcessInstance instance) {
        ProcessInstanceVO vo = new ProcessInstanceVO();
        vo.setId(instance.getId());
        vo.setProcessDefinitionId(instance.getProcessDefinitionId());
        vo.setProcessDefinitionKey(instance.getProcessDefinitionKey());
        vo.setStartUserId(instance.getStartUserId());
        vo.setStartTime(instance.getStartTime());
        vo.setEndTime(instance.getEndTime());
        vo.setBusinessKey(instance.getBusinessKey());
        
        // 设置流程定义名称
        ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery()
                .processDefinitionId(instance.getProcessDefinitionId())
                .singleResult();
        if (processDefinition != null) {
            vo.setProcessDefinitionName(processDefinition.getName());
        }
        
        // 设置状态
        if (instance.getEndTime() != null) {
            vo.setStatus("completed");
        } else {
            // 检查是否挂起
            ProcessInstance runtimeInstance = runtimeService.createProcessInstanceQuery()
                    .processInstanceId(instance.getId())
                    .singleResult();
            if (runtimeInstance != null && runtimeInstance.isSuspended()) {
                vo.setStatus("suspended");
            } else {
                vo.setStatus("active");
            }
        }
        
        return vo;
    }
    
    private ProcessInstanceVO convertRuntimeToVO(ProcessInstance instance) {
        ProcessInstanceVO vo = new ProcessInstanceVO();
        vo.setId(instance.getId());
        vo.setProcessDefinitionId(instance.getProcessDefinitionId());
        vo.setProcessDefinitionKey(instance.getProcessDefinitionKey());
        vo.setStartUserId(instance.getStartUserId());
        vo.setStartTime(instance.getStartTime());
        vo.setBusinessKey(instance.getBusinessKey());
        vo.setStatus("suspended"); // 运行时查询的都是挂起的实例
        
        // 设置流程定义名称
        ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery()
                .processDefinitionId(instance.getProcessDefinitionId())
                .singleResult();
        if (processDefinition != null) {
            vo.setProcessDefinitionName(processDefinition.getName());
        }
        
        return vo;
    }
    
    private List<ProcessInstanceVO.ActivityInfo> getCurrentActivities(String processInstanceId) {
        List<ProcessInstanceVO.ActivityInfo> activities = new ArrayList<>();
        
        // 获取当前任务
        List<Task> tasks = taskService.createTaskQuery()
                .processInstanceId(processInstanceId)
                .active()
                .list();
        
        for (Task task : tasks) {
            ProcessInstanceVO.ActivityInfo activity = new ProcessInstanceVO.ActivityInfo();
            activity.setActivityId(task.getTaskDefinitionKey());
            activity.setActivityName(task.getName());
            activity.setActivityType("userTask");
            activity.setAssignee(task.getAssignee());
            activity.setStartTime(task.getCreateTime());
            activities.add(activity);
        }
        
        // 获取其他类型的活动节点（如定时器等）
        List<Execution> executions = runtimeService.createExecutionQuery()
                .processInstanceId(processInstanceId)
                .list();
        
        for (Execution execution : executions) {
            if (execution.getActivityId() != null && !isUserTaskActivity(execution.getActivityId())) {
                ProcessInstanceVO.ActivityInfo activity = new ProcessInstanceVO.ActivityInfo();
                activity.setActivityId(execution.getActivityId());
                activity.setActivityType(getActivityType(execution.getActivityId()));
                // activity.setStartTime(execution.getStartTime());
                activities.add(activity);
            }
        }
        
        return activities;
    }
    
    private boolean isUserTaskActivity(String activityId) {
        // 这里可以根据需要判断活动类型
        // 实际项目中可能需要查询BPMN模型获取准确的类型
        return activityId.startsWith("task") || activityId.contains("Task");
    }
    
    private String getActivityType(String activityId) {
        // 简化实现，实际项目中应该从BPMN模型中获取
        if (activityId.contains("Timer")) return "timerEvent";
        if (activityId.contains("Gateway")) return "gateway";
        if (activityId.contains("Event")) return "event";
        return "activity";
    }
}